package network;

import algorithms.*;

import java.util.*;
import java.security.NoSuchAlgorithmException;

public class Network {
    Map<Integer, Vertex> vertices;
    Vector<Edge> edges;
    DeploymentAlgorithm algo;

    public Network() {
        vertices = new HashMap<Integer, Vertex>();
        edges = new Vector<Edge>();
        try {
            algo = DeploymentAlgorithmFactory.getDeploymentAlgorithm(DeploymentAlgorithmFactory.SumOfDegree);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public void addVertex(Vertex vertex) {
        vertices.put(vertex.getNum(), vertex);
    }

    public void addEdge(int vertex1, int vertex2, int val, HashMap<String, String> params) {
        Vertex v1 = vertices.get(vertex1);
        Vertex v2 = vertices.get(vertex2);

        Edge e = new Edge(v1, v2, val, params);
        edges.add(e);

        v1.setEdge(e);
        v2.setEdge(e);

    }

    public Set<Vertex> maximizeCentrality(int algo, int k, int n) throws NoSuchAlgorithmException {
        Set<Vertex> s = getRandomVertices(k);

        System.out.println("Random:");
        System.out.println(s);


        this.algo = DeploymentAlgorithmFactory.getDeploymentAlgorithm(algo);
        int centrality = this.algo.getCentrality(s);
        int lastCentrality = -1;
        while(n>0 && centrality != lastCentrality){
            n--;
            lastCentrality = centrality;

            //Step A
            int contrib = 0;
            Vertex smallest = null;
            int minContrib = Integer.MAX_VALUE;
            for(Vertex v: s){
                Set<Vertex> tmp = new HashSet<Vertex>(s);
                tmp.remove(v);
                contrib = centrality - this.algo.getCentrality(tmp);
                if(minContrib > contrib){
                    minContrib = contrib;
                    smallest = v;
                }
            }

            //Step B
            s.remove(smallest);
            centrality = this.algo.getCentrality(s);

            //Step C
            int maxContrib = Integer.MIN_VALUE;
            Vertex largest = null;
            for(Vertex w: vertices.values()){
                if(!s.contains(w)){
                    Set<Vertex> tmp2 = new HashSet<Vertex>(s);
                    tmp2.add(w);
                    contrib = this.algo.getCentrality(tmp2) - centrality;
                    if(maxContrib < contrib){
                        maxContrib = contrib;
                        largest = w;
                    }
                }
            }

            //Step D
            s.add(largest);

            //Step E
            centrality = this.algo.getCentrality(s);

        }

        return s;

    }

    private Set<Vertex> getRandomVertices(int k){
        Set<Vertex> s = new HashSet<Vertex>();

        while(s.size() < k){
            int rand = (int) (1 + (vertices.size() * Math.random()));
            s.add(vertices.get(rand));
        }

        return s;
    }
}
